//
// Ephi - simulation of magnetic fields and particles
// Copyright (C) 2007 Indrek Mandre <indrek(at)mare.ee>
// For more information please see http://www.mare.ee/indrek/ephi/
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//

// demonstration script

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "ephi.hpp"

#define WR 0.035
#define RADIUS 0.15
#define SPACING 0.01
#define COILPOT 10000
#define CURRENT 200000

class MyFieldGenerator : public StaticElement
{
public:
  // a very simple vortex
  void addFields (const vect3d& pos, vect3d& bfield, vect3d& efield)
  {
    prec_t d = sqrt(pos.x*pos.x+pos.y*pos.y);
    if ( d < 1e-23 ) return; // hack: don't do nan
    d = d * d * d;
    bfield += vect3d(-pos.y / d, pos.x / d, 0);
  }

  // empty, ignore
  void addPotential (const vect3d& pos, prec_t& potential) { return; }
  void draw(Screen& screen, const Screen::color& c) { return; }
  std::string get_povray_script () { return std::string(); }
  bool inContact (const vect3d& pos) { return false; }
};

int main (int argc, char *argv[])
{
  // example 1: simple coils within coils
  {
    Statics statics;
    // make one set of coils
    make_polywell_cube (statics, RADIUS, WR, SPACING, CURRENT, 0);
    // make another smaller one in the insides
    make_polywell_cube (statics, 0.05, 0.015, SPACING, -CURRENT, 0);

    // note: the radius of the coils is specific, but the side of
    // the cube is calculated from that factoring in the thickness and spacing
    // like this: prec_t rr = RADIUS + (WR * 2 + SPACING) / PREC_SQRT2;

    ElectroDynamics dyn(statics);
    Scene scene(dyn);
    Screen screen (800, 800, 0.75, 0.75);

    // calculate the data matrix (800x800 samples)
    scene.calc (screen);
    scene.set_coloring (0, true); // 0 = full gradient, true = logarithmic scale (even weakest fields have color)
    scene.render_lic (screen); // render line integral convolution
    screen.write ("test25_cwc_bfield_lic.bmp"); // write as bmp
    // PS: I use the ImageMagick command line tool "convert" to get a jpg:
    //   $ convert test25a.bmp -contrast -quality 90 test25.jpg
    // two additional bfield magnitude visualizations, no need to recalc
    scene.set_coloring (0, false); // smooth and linear
    scene.render_map (screen);
    screen.write ("test25_cwc_bfield.bmp");
    scene.set_coloring (20, true); // stepped and logarithmic
    scene.render_map (screen);
    screen.write ("test25_cwc_bfield_log_stepped.bmp");

    // change projection to "corner-cut"
    screen.set_axis (vect3d(0, 0, 0), vect3d(1, 1, 0).normal(), vect3d(0, 0, 1));
    scene.calc (screen);
    scene.set_coloring (0, true);
    scene.render_lic (screen);
    screen.write ("test25_cwc_bfield_lic_X.bmp");

    // write out povray script for this static setting - can be used to visualize and debug
    // install povray package and just run:
    //    povray -geometry 800x800 +A +Q9 +AM2 polywell.pov
    FILE *fout = fopen ("polywell.inc", "w");
    fprintf (fout, "%s", statics.get_povray_script().c_str());
    fclose (fout);
  }

  // example 2: demonstration on how to use manual coil placement
  {
    Statics statics;

    statics.addStaticElement (new StaticRing (CURRENT,
        vect3d(0, 0, 0), // position
        0.2,  // radius
        0.05, // WR - coil cross-section radius
        vect3d(1, 1, 0).normal() // direction, coil plane normal
    ));

    ElectroDynamics dyn(statics);
    Scene scene(dyn);
    Screen screen (800, 800, 0.75, 0.75);
    scene.calc (screen);
    scene.set_coloring (0, true);
    scene.render_lic (screen);
    screen.write ("test25_sc_bfield_lic.bmp");
  }
  
  // example 3: using a self-generated field
  {
    Statics statics;
    statics.addStaticElement (new MyFieldGenerator());

    ElectroDynamics dyn(statics);
    Scene scene(dyn);
    Screen screen (800, 800, 0.75, 0.75);
    scene.calc (screen);
    scene.set_coloring (0, true);
    scene.render_lic (screen);
    screen.write ("test25_sgf_bfield_lic.bmp");
  }

  return 0;
}

